/*
 * Project 1 phase 1
 * Efim Todorasco and Liviu Patrasco  
 */


import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.nio.IntBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.util.FPSAnimator;

public class Scene implements GLEventListener {
	protected static SceneGraphNode sceneGraphRoot = new SceneGraphNode(false);
	private static boolean pickNextFrame;
	private static double left, right, top, bottom, wid, hei, offt, offb, offl, offr;
	protected static int displayListID = -1;

	protected static SceneGraphNode circle = new Circle();
	protected static SceneGraphNode rectangle = new Rectangle();
	protected static SceneGraphNode triangle = new Triangle();
	protected static SceneGraphNode triangle2 = new Triangle2();
	protected static SceneGraphNode carret = new Paddle();
	protected static SceneGraphNode ellipse = new Ellipse();
	protected static SceneGraphNode tree = Tree.create(8);

	protected Point startPickedPoint = new Point(0,0);
	protected Point endPickedPoint;
 
	private SceneGraphNode pickedObj; 
	protected double wcoord[] = new double[4];
	protected int viewport[] = new int[4];
	protected double realY = 0;
	protected double mvmatrix[] = new double[16];
	protected double projmatrix[] = new double[16];
	protected char c;
	protected boolean orthoFlag; 
	protected boolean zoomFlag;
	protected float dx = 0;
	protected float dy = 0;
	protected double UNIT = 4;
	protected GLCanvas canvas; 
	
	public GLCanvas getCanvas() {
		// Fix for background flickering
		// System.setProperty("sun.awt.noerasebackground", "true");

		GLProfile profile = GLProfile.getDefault();
		GLCapabilities capabilities = new GLCapabilities(profile);
		canvas = new GLCanvas(capabilities);
		canvas.addGLEventListener(this);
		canvas.setFocusable(true);
		canvas.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				pickNextFrame = true;
				startPickedPoint = new Point(e.getX(), e.getY());
			}
		});
		canvas.addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent e) {
				endPickedPoint = startPickedPoint;
				startPickedPoint = new Point(e.getX(), e.getY());
				dx = (startPickedPoint.x - endPickedPoint.x) * (float)((2*wid) / canvas.getWidth());
				dy = (startPickedPoint.y - endPickedPoint.y) * (float)((2*hei) / canvas.getHeight());
				if (pickedObj != null) {
				pickedObj.translateX += dx;
				pickedObj.translateY -= dy;
				displayListID = -1;
				}
			}
		});
		canvas.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				c = e.getKeyChar();
				if (c == '+' || c == '-' || c == 'r'|| c == 'c' || c == 'v') {
					if (pickedObj != null){
						if(c == '+') pickedObj.scale += .1f;
						if(c == '-') pickedObj.scale -= .1f;
						if(c == 'r') sceneGraphRoot.removeChild(pickedObj);
						if(c == 'c') pickedObj.rotation += 5;
						if(c == 'v') pickedObj.rotation -= 5;
						displayListID = -1;
					}
				} 
				if(c == 'x' || c == 'z' ) {
					if(c == 'x' && UNIT > 0)  UNIT -= .2f;
					if(c == 'z' && UNIT < 10) UNIT += .2f;	
					zoomFlag = true;
				}
				if(c == 'a' || c == 's' || c == 'd'|| c == 'w') {
					if(c == 'w') {top -= .1; bottom -= .1; offt -= .1; offb -= .1;};
					if(c == 'a') {left += .1; right += .1; offl += .1; offr += .1;};
					if(c == 's') {bottom += .1; top += .1; offb += .1; offt += .1;};
					if(c == 'd') {right -= .1; left -= .1; offr -= .1; offl -= .1;};
					orthoFlag = true;
				}
			}

		});
		
/*************************************************************/
		triangle2.translateY = 1;
		circle.translateX = -1;
		triangle.translateX= 1;
		carret.translateX = -.4f;
		carret.translateY = -1;
		ellipse.scale = .5f;		
		ellipse.translateY = -.5f;
		sceneGraphRoot.addChild(triangle);
		sceneGraphRoot.addChild(rectangle);
		sceneGraphRoot.addChild(carret);
		sceneGraphRoot.addChild(ellipse);
		sceneGraphRoot.addChild(circle);
	    sceneGraphRoot.addChild(triangle2);
	    sceneGraphRoot.addChild(tree);
/*************************************************************/				

		return canvas;
	}

	public void display(GLAutoDrawable drawable) {
		GL2 gl = drawable.getGL().getGL2();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		GLU glu = GLU.createGLU(gl);
		int viewport[] = new int[4];

		if (pickNextFrame) {
			gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
			gl.glMatrixMode(GL2.GL_PROJECTION);
			gl.glPushMatrix();
			gl.glLoadIdentity();
			glu.gluPickMatrix((double)startPickedPoint.x, (double)(viewport[3] - startPickedPoint.y), 1, 1, viewport, 0);
			gl.glOrtho(left, right, bottom, top, -1, 1);
			gl.glMatrixMode(GL2.GL_MODELVIEW);
			if (!sceneGraphRoot.getPicked(drawable).isEmpty())
				pickedObj = sceneGraphRoot.getPicked(drawable).get(sceneGraphRoot.getPicked(drawable).size()-1);
			else pickedObj = null;
			System.out.println(pickedObj);
			gl.glMatrixMode(GL2.GL_PROJECTION);
			gl.glPopMatrix();
			gl.glMatrixMode(GL2.GL_MODELVIEW);
			pickNextFrame = false;
		}
		if(zoomFlag) {
			reshape(drawable, 0, 0, canvas.getWidth(), canvas.getHeight());
			zoomFlag = false;
		}
		if (orthoFlag) {
			reshape(drawable, 0, 0, canvas.getWidth(), canvas.getHeight());
			orthoFlag = false;
		}
		if (displayListID == -1) {
			displayListID = 1;
			gl.glNewList(displayListID, GL2.GL_COMPILE_AND_EXECUTE);
			sceneGraphRoot.render(drawable);
			gl.glEndList();
		} else
			gl.glCallList(displayListID);
		//sceneGraphRoot.render(drawable);
		//sceneGraphRoot.rotation++;
		//gl.glRotatef(1, 0, 0, 1);
	}

	public void dispose(GLAutoDrawable drawable) {
	}

	public void init(GLAutoDrawable drawable) {
		GL2 gl = drawable.getGL().getGL2();
		gl.glClearColor(0, 0, 0, 0);
		IntBuffer selectBuffer = Buffers.newDirectIntBuffer(3);
		gl.glSelectBuffer(selectBuffer.capacity(), selectBuffer);
		FPSAnimator fps = new FPSAnimator(drawable, 30);
		fps.start();
		
	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		if (width < height) {
			left = -UNIT / 2;
			right = UNIT / 2;
			top = (double)height / width * UNIT / 2;
			bottom = -top;
		} else {
			top = UNIT / 2;
			bottom = -UNIT / 2;
			right = (double)width / height * UNIT / 2;
			left = -right;	
		}
		wid = right; hei = top; top += offt; bottom += offb; left += offl; right += offr;
		GL2 gl = drawable.getGL().getGL2();
		gl.glMatrixMode(GL2.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrtho(left, right, bottom, top, -1, 1);
		gl.glMatrixMode(GL2.GL_MODELVIEW);
	
	}	
}

